package ocmd

import (
	"encoding/json"
	"osiris/dto"
	"osiris/errors"
	"osiris/logger"
	"osiris/ocrypto/ed25519"
	"osiris/p2p"
	"sync"

	peer "github.com/libp2p/go-libp2p/core/peer"
	ma "github.com/multiformats/go-multiaddr"
)

// PingHandler ping命令handler
type PingHandler struct{}

// Handle ping ping命令： ping [full muultiaddr]，ping另一个P2P节点，互相验证身份、互换公钥、PeerStore存储
//
//	@receiver handler
//	@param inputs
//	@param wg
//	@return bool
//	@return error
func (handler *PingHandler) Handle(inputs []string, wg *sync.WaitGroup) error {
	errorOccured := true
	defer func() {
		if wg != nil && errorOccured {
			wg.Done()
		}
	}()

	if len(inputs) < 2 {
		return &errors.CommandInputError{
			Msg: "not enough arguments!",
		}
	}

	target := inputs[1]
	ipfsaddr, err1 := ma.NewMultiaddr(target)
	if err1 != nil {
		logger.Error(map[string]interface{}{"[ocmd] [Ping] transform target": err1})
		return err1
	}

	pid, err2 := ipfsaddr.ValueForProtocol(ma.P_IPFS)
	if err2 != nil {
		logger.Error(map[string]interface{}{"[ocmd] [Ping] transform target": err2})
		return err2
	}

	peerID, err3 := peer.Decode(pid)
	if err3 != nil {
		logger.Error(map[string]interface{}{"[ocmd] [Ping] transform target": err3})
		return err3
	}

	// Decapsulate the /ipfs/<peerID> part from the target
	// /ip4/<a.b.c.d>/ipfs/<peer> becomes /ip4/<a.b.c.d>
	targetPeerAddr, _ := ma.NewMultiaddr("/ipfs/" + peerID.String())
	targetAddr := ipfsaddr.Decapsulate(targetPeerAddr)
	p2p.AddAddr(peerID, targetAddr)
	//p2p.StorePeerMultiaddr(peerID, targetAddr)

	//log.Println(target)              // /ip4/127.0.0.1/tcp/10000/p2p/Qmesr72dy3T21Ro6hTP1mTvi9VC7XZ3T5fSzrgaxVRzCgA   type:string
	//log.Println(peerID)              //Qmesr72dy3T21Ro6hTP1mTvi9VC7XZ3T5fSzrgaxVRzCgA   type:peer.ID
	//log.Println(peerID.String())     //Qmesr72dy3T21Ro6hTP1mTvi9VC7XZ3T5fSzrgaxVRzCgA   type:string
	//log.Println(targetAddr)          // /ip4/127.0.0.1/tcp/10000    type:ma.Multiaddr
	//log.Println(targetAddr.String()) // /ip4/127.0.0.1/tcp/10000    type:string

	errorOccured = false
	peerDto := dto.PeerDto{
		BaseDto: dto.BaseDto{
			Code: dto.CODE_PING,
		},
		SenderPeerID:     p2p.GetSelfID().String(),
		SenderMultiaddrs: p2p.GetSelfMultiaddrStrs(),
		SenderPubKey:     ed25519.GetPeerPubKeyStr(),
	}
	peerDto.HashAndSign()
	peerDtoJson, err4 := json.Marshal(peerDto)
	if err4 != nil {
		logger.Error(map[string]interface{}{"[ocmd] [Handle ping] marshal peerDto": err4})
		return err4
	}
	p2p.OpenStream(p2p.PingProtocol{}, peerID, string(peerDtoJson), wg)

	return nil
}

func (hadnler *PingHandler) PrintHelp() {
	logger.Println("usage: ping [full muultiaddr]")
}
